package com.iteaj.iot.serial;

import com.fazecast.jSerialComm.SerialPort;
import com.iteaj.iot.ProtocolException;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * 串口创建器
 */
public class SerialPortCreator {

    /**
     * 获取已经打开的串口
     * @param com
     * @return
     */
    public static Optional<SerialClient> get(String com) {
        return Optional.ofNullable(getIotClient(new SerialConnectProperties(com)));
    }

    /**
     * 返回可用的串口列表
     * @return
     */
    public static List<SerialPort> available() {
        return Arrays.asList(SerialPort.getCommPorts());
    }

    /**
     * 串口是否打开
     * @param com
     * @return
     */
    public static boolean isOpen(String com) {
        Optional<SerialClient> client = get(com);
        return client.isPresent() ? client.get().isOpen() : false;
    }

    /**
     * 打开已经存在的串口
     * @param com
     * @return
     */
    public static SerialClient opened(String com) {
        SerialClient serialClient = getIotClient(new SerialConnectProperties(com));
        if(serialClient == null) {
            throw new SerialProtocolException("串口不存在["+com+"]");
        } else if(!serialClient.isOpen()) {
            serialClient.open();
        }

        return serialClient;
    }

    /**
     * 关闭指定串口
     * @param com
     * @return
     */
    public static boolean close(String com) {
        SerialClient client = SerialComponent.instance().getClient(new SerialConnectProperties(com));
        if(client != null) {
            return client.close();
        } else {
            return false;
        }
    }

    /**
     * 打开指定串口
     * @param properties
     * @return
     */
    public static synchronized SerialClient open(SerialConnectProperties properties) {
        SerialClient serialClient = getIotClient(properties);
        if(serialClient == null) {
            serialClient = SerialComponent.instance().createNewClient(properties);
            serialClient.init(null);
            if(!serialClient.open()) {
                throw new SerialProtocolException("打开串口失败["+properties+"]");
            } else {
                SerialComponent.instance().addClient(properties, serialClient);
            }
        } else {
            throw new SerialProtocolException("串口已经创存在["+properties+"]");
        }

        return serialClient;
    }

    /**
     * 异步打开串口
     * @param connectProperties 串口配置
     * @param packetSize 完整包长度  如果是0则只要有数据就读取
     * @return
     */
    public static SerialClient openByAsync(SerialConnectProperties connectProperties, int packetSize) {
        SerialClient serialClient = open(connectProperties);
        serialClient.addDataListener(new SerialPortPacketProtocolListener(packetSize, connectProperties, getProtocolHandle()));
        return serialClient;
    }

    /**
     * 异步打开串口
     * @param connectProperties 串口配置
     * @param packetSize 完整包长度  如果是0则只要有数据就读取
     * @return
     */
    public static SerialClient openByAsync(SerialConnectProperties connectProperties, int packetSize, SerialEventProtocolHandle handle) {
        SerialClient serialClient = open(connectProperties);
        serialClient.addDataListener(new SerialPortPacketProtocolListener(packetSize, connectProperties, handle));
        return serialClient;
    }

    /**
     * 异步打开串口
     * @param connectProperties 串口配置
     * @param delimiter 完整报文之间的分隔符
     * @return
     */
    public static SerialClient openByAsync(SerialConnectProperties connectProperties, byte[] delimiter) {
        SerialClient serialClient = open(connectProperties);
        serialClient.addDataListener(new SerialPortDelimiterListener(delimiter, connectProperties, getProtocolHandle()));
        return serialClient;
    }

    /**
     * 异步打开串口
     * @param connectProperties 串口配置
     * @param delimiter 完整报文之间的分隔符
     * @return
     */
    public static SerialClient openByAsync(SerialConnectProperties connectProperties, byte[] delimiter, SerialEventProtocolHandle handle) {
        SerialClient serialClient = open(connectProperties);
        serialClient.addDataListener(new SerialPortDelimiterListener(delimiter, connectProperties, handle));
        return serialClient;
    }

    protected static SerialEventProtocolHandle getProtocolHandle() {
        SerialEventProtocolHandle protocolHandle = SerialComponent.instance().getProtocolHandle();
        return protocolHandle != null ? protocolHandle : SerialEventProtocolHandle.LOGGER_HANDLE;
    }

    protected static SerialClient getIotClient(SerialConnectProperties properties) throws ProtocolException {
        return SerialComponent.instance().getClient(properties);
    }
}
